package edu.hd4ic.algorithm.base;

import edu.hd4ic.edu.hd4ic.data.ProcessingImageDataContainer;
import org.apache.log4j.Logger;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.util.LinkedList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: morfant
 * Date: 25.12.12
 * Time: 20:42
 * To change this template use File | Settings | File Templates.
 */
public abstract class AbstractHDBasedAlgorithm implements HDBasedAlgorithm {
    private static final Logger LOGGER = Logger.getLogger(AbstractHDBasedAlgorithm.class);

    protected double calculationTreshold;

    @Override
    public List<HDValue> compareImage(ProcessingImageDataContainer firstImageContainer,
                                      ProcessingImageDataContainer secondImageContainer,
                                      double calculationThreshold) {

        this.calculationTreshold=calculationThreshold;

        final int BAND_NUMBER = 0;
        Image firstImage = firstImageContainer.getEdgeInputImage() != null ?
                firstImageContainer.getEdgeInputImage() :
                firstImageContainer.getInputImage();
        Image secondImage = secondImageContainer.getEdgeInputImage() != null ?
                secondImageContainer.getEdgeInputImage() :
                secondImageContainer.getInputImage();
        Raster firstImageRaster = ((BufferedImage) firstImage).getData();
        int firstImageRasterWidth = firstImageRaster.getWidth();
        int firstImageRasterHeight = firstImageRaster.getHeight();
        Raster secondImageRaster = ((BufferedImage) secondImage).getData();
        int secondImageRasterWidth = secondImageRaster.getWidth();
        int secondImageRasterHeight = secondImageRaster.getHeight();

        int widthDifference = firstImageRasterWidth - secondImageRasterWidth;
        int heightDifference = firstImageRasterHeight - secondImageRasterHeight;
        int numberOfIterationOnWidth = Math.abs(widthDifference);
        int numberOfIterationOnHeight = Math.abs(heightDifference);
        int imageBlockWidth, imageBlockHeight;
        if ((widthDifference >= 0) && (heightDifference >= 0)) {
            //first Image is bigger
            imageBlockWidth = secondImageRasterWidth;
            imageBlockHeight = secondImageRasterWidth;
        } else {
            if ((widthDifference < 0) && (heightDifference < 0)) {
                //second Image is bigger
                imageBlockWidth = firstImageRasterWidth;
                imageBlockHeight = firstImageRasterHeight;
            } else {
                throw new IllegalArgumentException("Размеры изображений не позволяют их сравнить!");
            }
        }

        int[] firstImageRasterDataBlock, secondImageRasterDataBlock;
        int widthOffset, heightOffset, i, j;
        double undirectedDistance;
        List<HDValue> result = new LinkedList<HDValue>();

        for (widthOffset = 0; widthOffset <= numberOfIterationOnWidth; widthOffset++) {
            for (heightOffset = 0; heightOffset <= numberOfIterationOnHeight; heightOffset++) {
                if (widthDifference >= 0) {
                    firstImageRasterDataBlock =
                            firstImageRaster.
                                    getSamples(widthOffset, heightOffset, imageBlockWidth, imageBlockHeight, BAND_NUMBER, (int[]) null);
                    secondImageRasterDataBlock =
                            secondImageRaster.
                                    getSamples(0, 0, imageBlockWidth, imageBlockHeight, BAND_NUMBER, (int[]) null);
                } else {
                    firstImageRasterDataBlock =
                            firstImageRaster.
                                    getSamples(0, 0, imageBlockWidth, imageBlockHeight, BAND_NUMBER, (int[]) null);
                    secondImageRasterDataBlock =
                            secondImageRaster.
                                    getSamples(widthOffset, heightOffset, imageBlockWidth, imageBlockHeight, BAND_NUMBER, (int[]) null);
                }

                undirectedDistance =
                        Math.max(
                                calculateDirectDistance(firstImageRasterDataBlock,
                                        secondImageRasterDataBlock,
                                        imageBlockWidth, imageBlockHeight),
                                calculateDirectDistance(secondImageRasterDataBlock,
                                        firstImageRasterDataBlock,
                                        imageBlockWidth, imageBlockHeight));
                if (undirectedDistance <= calculationThreshold) {
                    if (widthDifference >= 0) {
                        result.add(new HDValue(widthOffset, heightOffset, 0, 0, undirectedDistance));
                    } else {
                        result.add(new HDValue(0, 0, widthOffset, heightOffset, undirectedDistance));
                    }
                }
            }
        }

        return result;
    }

    abstract protected double calculateDirectDistance(int[] firstImageDataBlock,
                                                      int[] secondImageDataBlock,
                                                      int width,
                                                      int height);
}
